﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;

namespace SimpleIR
{
	/// <summary>
	/// Represents simple variable expressions.
	/// </summary>
	public sealed class IRVarExp
	{
		private readonly IRVarName m_name;
		private readonly IRType m_type;

		[ContractInvariantMethod]
		private void ObjectInvariant()
		{
			Contract.Invariant(this.m_name != null);
			Contract.Invariant(this.m_type != null);
		}

		public IRVarExp(IRType etype, IRVarName ln)
		{
			Contract.Requires(etype != null);
			Contract.Requires(ln != null);

			this.m_name = ln;
			this.m_type = etype;
		}

		public override String ToString()
		{ return this.m_name.ToString(); }

		public IRVarName Name 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<IRVarName>() != null);

				return this.m_name; 
			} 
		}
		
		public IRType VarType 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<IRType>() != null);

				return this.m_type; 
			} 
		}
	}

	/// <summary>
	/// Represents simple literal expressions.
	/// </summary>
	public sealed class IRLiteralExp
	{
		//List of possible values that this literal might represent
		private readonly long m_litval = Int64.MinValue;
		private readonly double m_flit = Double.NaN;
		private readonly String m_strlit = null;
		private readonly bool m_isnull = false;

		private readonly IRType m_type;

		[ContractInvariantMethod]
		private void ObjectInvariant()
		{
			Contract.Invariant(this.m_type != null);
		}

		private IRLiteralExp(IRType etype, long lv, double dv, String sv, bool inull)
		{
			Contract.Requires(etype != null);

			this.m_litval = lv;
			this.m_flit = dv;
			this.m_strlit = sv;
			this.m_isnull = inull;

			this.m_type = etype;
		}

		public static IRLiteralExp MakeSignedIntegralLiteral(IRType etype, long lv)
		{
			Contract.Requires(etype != null && (etype is IRSignedIntegerType));
			return new IRLiteralExp(etype, lv, Double.NaN, null, false);
		}

		public static IRLiteralExp MakeFloatLiteral(IRType etype, double fv)
		{
			Contract.Requires(etype != null && (etype is IRFloatingPointType));
			return new IRLiteralExp(etype, 0, fv, null, false);
		}

		public static IRLiteralExp MakeStringLiteralExp(IRType etype, String s)
		{
			Contract.Requires(etype != null && (etype is IRPtrType) && (((IRPtrType)etype).PtrTargetType is IRClassType));
			return new IRLiteralExp(etype, 0, Double.NaN, s, false);
		}

		public static IRLiteralExp MakeNullLiteralExp(IRPtrType etype)
		{
			Contract.Requires(etype != null);
			return new IRLiteralExp(etype, 0, Double.NaN, null, true);
		}

		public override String ToString()
		{
			if(this.m_isnull)
				return "null";
			else if(this.m_type is IRPrimitiveType)
			{
				IRPrimitiveType pty = (IRPrimitiveType)this.m_type;
				if(pty is IRSignedIntegerType)
					return this.m_litval.ToString();
				else
					return this.m_flit.ToString();
			}
			else
				return "\"" + this.m_strlit + "\"";
		}

		public IRType LiteralType 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<IRType>() != null);

				return this.m_type; 
			} 
		}

		public long IntVal 
		{ 
			get 
			{
				Contract.Requires(this.LiteralType is IRSignedIntegerType);

				return this.m_litval; 
			} 
		}

		public double FloatVal 
		{ 
			get 
			{
				Contract.Requires(this.LiteralType is IRFloatingPointType);

				return this.m_flit; 
			} 
		}

		public String StringVal
		{
			get
			{
				Contract.Requires((this.LiteralType is IRClassType) && (this.LiteralType != null));
				Contract.Ensures(Contract.Result<String>() != null);

				return this.m_strlit;
			}
		}
	}
}
